;定义常量（作用和C语言中的#define一样）
VIDEO_CHAR_MAX_COUNT equ 2000 ;默认屏幕最多显示字符数。

org 0x7c00 ;如果没有该行将无法正确打印要显示的字符串

;初始化段寄存器
mov ax,cs
mov ds,ax ;ds指向与cs相同的段
mov ax,0xb800
mov es,ax ;本程序中es专用于指向显存段

;清屏
call func_clear_screen

;打印字符串
mov si,string1
mov di,0 ;在屏幕第1行显示
call func_print_string

stop:
hlt
jmp stop 

;清屏函数（将屏幕写满空格就实现了清屏）
;输入参数：无。
;输出参数：无。
func_clear_screen:
mov ah,0x00 ;黑底黑字
mov al,' '  ;空格
mov cx,VIDEO_CHAR_MAX_COUNT
.start_blank:
mov bx,cx ;bx=(cx-1)*2 字符对应的显存地址（从屏幕右下角往前清屏）
dec bx
shl bx,1
mov [es:bx],ax
loop .start_blank
ret

;打印字符串函数
;输入参数：ds:si，di。
;输出参数：无。
;si 表示字符串起始地址，以0为结束符。
;di 表示字符串在屏幕上显示的起始位置（0~1999）
func_print_string:
mov ah,0x07 ;ah 表示字符属性 黑底白字
shl di,1 ;乘2（屏幕上每个字符对应2个显存字节）
.start_char: ;以点开头的标号为局部标号，完整形式是 func_print_string.start_char
mov al,[si]
cmp al,0
jz .end_print
mov [es:di],ax
inc si
add di,2
jmp .start_char
.end_print:
ret

string1:db "Hello GrapeOS!",0

times 510-($-$$) db 0
db 0x55,0xaa